
import Foundation

struct Position {
    var x: Distance
    var y: Distance
}

extension Position {
    func minus(_ p: Position) -> Position {
        return Position(x: x - p.x, y: y - p.y)
    }
    var length: Double {
        return sqrt(x * x + y * y)
    }
}

typealias Distance = Double

typealias Region = (Position) -> Bool

func circle(radius: Distance) -> Region {
    return { point in
        point.length <= radius
    }
}

// 半径为5，圆心为原点的圆
circle(radius: 5)

func circle2(radius: Distance, center: Position) -> Region {
    return { point in point.minus(center).length <= radius }
}

// 半径为10， 圆心为(5, 5)的圆
circle2(radius: 10, center: .init(x: 5, y: 5))

func shift(_ region: @escaping Region, by offset: Position) -> Region {
    return { point in region(point.minus(offset)) }
}

// 半径为10， 圆心为(5, 5)的圆
let shifted = shift(circle(radius: 10), by: Position(x: 5, y: 5))

// 区域以外的点
func invert(_ region: @escaping Region) -> Region {
    return { point in !region(point)}
}

// 两个区域的交集
func intersect(_ region: @escaping Region, with other: @escaping Region) -> Region {
    return { point in region(point) && other(point) }
}

// 两个圆区域的并集
func union(_ region: @escaping Region, with other: @escaping Region) -> Region {
    return { point in region(point) || other(point) }
}

// 属于第一个区域且不属于第二个区域
func subtract(_ region: @escaping Region, from original: @escaping Region) -> Region {
    return intersect(original, with: invert(region))
}

struct RangeRegion {
    let lookup: (Position) -> Bool

    func shift(_ postion: Position) -> RangeRegion {
        return RangeRegion(lookup: { (p) -> Bool in
            return self.lookup(p.minus(postion))
        })
    }

    func invert() -> RangeRegion {
        return RangeRegion(lookup: { (p) -> Bool in
            return !self.lookup(p)
        })
    }

    func intersect(_ other: @escaping Region) -> RangeRegion {
        return RangeRegion(lookup: { (p) -> Bool in
            return self.lookup(p) && other(p)
        })
    }
}

let rangeRegion = RangeRegion(lookup: circle(radius: 5))
RangeRegion(lookup: circle(radius: 5)).intersect(circle(radius: 3)).lookup(Position(x: 2.1, y: 2.1))
rangeRegion.shift(Position(x: 6, y: 0)).shift(Position(x: -6, y: 0)).lookup(Position(x: 0, y: 0))

let array = [0, 1, 2, 3]

extension Array {
    func myFilter(_ include: (Element) -> Bool) -> [Element] {
        var filterArray: [Element] = []
        self.forEach { (element) in
            if include(element) {
                filterArray.append(element)
            }
        }
        return filterArray
    }

    func myReduce<Result>(_ initial: Result, _ nextPartial: (Result, Element) -> Result) -> Result {
        var sum = initial
        for item in self {
            sum = nextPartial(sum, item)
        }
        return sum
    }

    func myMap<T>(_ transform: (Element) -> T) -> [T] {
        var mapArray: [T] = []
        self.forEach { (element) in
            mapArray.append(transform(element))
        }
        return mapArray
    }
}

array.myMap { (item) -> String in
    return "\(item + 1)"
}

array.myReduce(0) { (result, element) -> Int in
    return result + element
}









